*****
Build
*****

.. highlight:: none


Overview
========

If you need to, install a C build toolchain by::

    sudo ./installc

``installc`` uses the system's package manager.

.. note::
    Packages can be uninstalled again with :option:`-r`.

Configure the build by::

    ./configure wwwgroup=www-data cgidir=/usr/lib/cgi-bin

But replace "www-data" with the group your web server runs as and
:file:`/usr/lib/cgi-bin` with your web server's :file:`/cgi-bin`
directory.

Compile suCGI by::

    make

See below for details.


Configuration
=============

The build configuration is stored in the :file:`Makefile`.

The :file:`Makefile` is generated from :file:`Makefile.in` by 
:command:`./configure`, which replaces defaults with values more
appropriate to the system.

The configuration detected by `./configure` is stored in
:file:`config.status`. :file:`config.status` is a shell script,
calling which regenerates the :file:`Makefile` using the
most recent configuration.

*configure* is controlled by:

* A configuration file (see `Configuration files`_ below)
* The environment (see `Macros`_ below)
* Arguments (see :command:`./configure -h` and the `GNU Coding Standards`_, chap. 7)

suCGI does *not* use Autoconf_; *configure* and its configuration files
are hand-written shell scripts; so you can debug them if you need to.

The same goes for the :file:`Makefile`. However, be careful to edit
:file:`Makefile.in`, the template from which the :file:`Makefile` is generated,
*not* the :file:`Makefile` itself, or else your changes may get overwritten.


Configuration files
-------------------

suCGI ships with four build configurations, which can be found in the
:file:`conf` sub-directory of the source tree.

================== ===========
Filename           Purpose
================== ===========
:file:`prod.env`   Production
:file:`devel.env`  Development
:file:`posix.env`  Fallback
================== ===========

Use :file:`prod.env` for production and :file:`devel.env` for development.

:file:`posix.env` disables GNU extensions to C99 and only uses tests for
compiler flags that are either required by some compilers or required
by POSIX.1-2008_. It is intended as a fallback if no working build
configuration can be created by using :file:`prod.env`.

For example,

.. code:: bash

    ./configure --conf=posix

selects :file:`posix.env`.


Macros
------

============================ =================================================
Macro                        Description
============================ =================================================
:c:macro:`GRP_T`             getgrouplist_ group ID type
:c:macro:`NGRPS_T`           setgroups_ number of groups type
:c:macro:`MAX_UID_VAL`       Largest value representable by :c:type:`uid_t`
:c:macro:`MAX_GID_VAL`       Largest value representable by :c:type:`gid_t`
:c:macro:`MAX_GRP_VAL`       Largest value representable by :c:macro:`GRP_T`
:c:macro:`MAX_NGRPS_VAL`     Largest value representable by :c:macro:`NGRPS_T`
:c:macro:`HAVE_SYS_PARAMS_H` Is :file:`sys/params.h` available?
:c:macro:`HAVE_FEATURES_H`   Is :file:`features.h` available?
:c:macro:`NDEBUG`            Disable assertions?
:c:macro:`NATTR`             Disable attributes?
:c:macro:`TESTING`           Build for testing?
:c:macro:`LINT`              Interpreted by a linter?
============================ =================================================

.. note::
    Boolean values are set using 1 for true and 0 for false.

.. danger::
    Test builds are insecure!

Macros can be set with *configure*'s :option:`-D` flag or in :file:`config.h`.
For example,

.. code:: bash

    ./configure -D NDEBUG
    printf '#define NDEBUG\n' >>config.h

are equivalent.


Arguments
---------

*configure* conforms to the `GNU Coding Standards`_, (chap. 7), save for
that it does *not* support cross-compiling (i.e., the :option:`--build`,
:option:`--host`, and :option:`--target` options) and passes unrecognised
options to the C compiler if the compiler supports them.


Run-time configuration
======================

suCGI's run-time behaviour is configured at compile-time.
See :file:`config.h.tpl` for details.

Defaults are set in :file:`params.h`. Every macro in :file:`params.h` can be
overridden by using *configure*'s or the compiler's :option:`-D` flag or by
defining a macro of the same name in :file:`config.h`.


Makefile targets
================

The :file:`Makefile` conforms to the `GNU Coding Standards`_
and supports the following 'phony' targets:

================ ============================================================
Target           Description
================ ============================================================
all              Alias for "sucgi" and the default target.
check            Compile and run tests
depend           Generate dependency graph. [#depend]_
mockcheck        Compile and run tests with mock-up system calls.
tidy             Delete backups, logs, and temporary files.
mostlyclean      `make tidy` and delete binaries and libraries.
clean            `make mostlyclean` and delete distribution files.
mrproper         `make clean` and delete caches, coverage data, and tags.
distclean        `make mrproper` and delete the build configuration.
maintainer-clean `make distclean` and delete dependency files and callgraphs.
dist             Make a distribution tarball.
distcheck        Run `make check` from a distribution tarball.
install          Install suCGI.
uninstall        Uninstall suCGI.
================ ============================================================


.. [#depend] Requires cscope_ and a `sed` that supports :option:`-i`
             (the GNU, BSD, and illumos ones do).


Troubleshooting
===============

*configure* fails
-----------------

Try the POSIX build configuration (see `Configuration files`_ above). If
that, too, fails re-direct the output of *configure* to :file:`config.mk`
to save the configuration that is detected before the failure:

.. code:: bash

    ./configure >config.mk

Then copy :file:`Makefile.in` to :file:`Makefile`, but uncomment the line
``#include config.mk``:

.. code:: bash

    sed 's/#\(include config.mk\)/\1/' Makefile.in >Makefile

If suCGI still fails to compile, you need to add appropriate definitions
for :c:macro:`DGRP_T`, :c:macro:`MAX_GRP_VAL`, :c:macro:`NGRPS_T`,
:c:macro:`MAX_NGRPS_VAL`, :c:macro:`MAX_UID_VAL`, and :c:macro:`MAX_GID_VAL`
to :c:macro:`CPPFLAGS`. For example:

.. code:: bash

    cat <<-EOF >>config.mk
    CPPFLAGS = \
        -DGRP_T=grp_t \
        -DMAX_GRP_VAL=UINT_MAX \
        -DNGRPS_T=size_t \
        -DMAX_NGRPS_VAL=SIZE_MAX \
        -DMAX_UID_VAL=UINT_MAX \
        -DMAX_GID_VAL=UINT_MAX
    EOF

See `Macros`_ above for details. 

"size of unnamed array is negative"
-----------------------------------

There is an error in the build configuration.

The message should indicate which setting is wrong.
For example,

.. code:: none

    main.c: In function 'main':
    macros.h:28:41: error: size of unnamed array is negative
       28 | #define ASSERT(cond) ((void) sizeof(char[(cond) ? 1 : -1]))
          |                                         ^
    main.c:278:5: note: in expansion of macro 'ASSERT'
      278 |     ASSERT(sizeof(USER_DIR) > 1U);
          |     ^~~~~~

indicates that the macro USER_DIR expands to a string that is too short.

Object files are recompiled needlessly
--------------------------------------

Your archiver may set the file modification time to zero.
Try adding :option:`-U`.

Disabling automatic updates of the Makefile
-------------------------------------------

The `GNU Coding Standards`_ require that the Makefile is updated whenever
one of the files it depends on changes. Rename or remove :file:`config.status`
to disable this behaviour.

Raising the number of groups suCGI can handle
---------------------------------------------

If the number of groups a user is a member of exceeds the value of
:c:macro:`MAX_NGROUPS` (see :file:`params.h`), CGI scripts of that
user will only be run with the permissions of an *arbitrary*
subset of those groups.

The limit can be changed in :file:`config.h` or
by using *configure*'s :option:`-D` flag:

.. code:: bash

    $ ./configure -D MAX_NGROUPS=65536
    [...]
    $ make
    [...]
    $ ./sucgi -c | grep -E ^MAX_NGROUPS=
    MAX_NGROUPS=65536

